package leetcode.prefixsum;

import java.util.HashMap;
import java.util.Map;

/**
 * 560. 和为 K 的子数组
 * 给你一个整数数组 nums 和一个整数 k ，请你统计并返回 该数组中和为 k 的子数组的个数 。
 * <p>
 * <p>
 * <p>
 * 示例 1：
 * <p>
 * 输入：nums = [1,1,1], k = 2
 * 输出：2
 * 示例 2：
 * <p>
 * 输入：nums = [1,2,3], k = 3
 * 输出：2
 */
public class SubarraySum {

    int ans = 0;


    /**
     * 推荐
     *
     * @param nums
     * @param k
     * @return
     */
    public int subarraySum0(int[] nums, int k) {

        int count = 0, preSum = 0;
        Map<Integer, Integer> map = new HashMap<>();
        map.put(0, 1);

        for (int i = 0; i < nums.length; i++) {
            preSum = preSum + nums[i];

            if (map.containsKey(preSum - k)) {
                count = count + map.get(preSum - k);
            }
            map.put(preSum, map.getOrDefault(preSum, 0) + 1);
        }
        return count;

    }

    /**
     * 前缀和
     *
     * @param nums
     * @param k
     * @return
     */
    public int subarraySum(int[] nums, int k) {
        int len = nums.length;
        // 计算前缀和数组
        int[] preSum = new int[len + 1];
        preSum[0] = 0;
        for (int i = 0; i < len; i++) {
            preSum[i + 1] = preSum[i] + nums[i];
        }

        int count = 0;
        for (int left = 0; left < len; left++) {
            for (int right = left; right < len; right++) {
                // 区间和 [left..right]，注意下标偏移
                if (preSum[right + 1] - preSum[left] == k) {
                    count++;
                }
            }
        }
        return count;
    }


    /**
     * 子数组要求连续哦，不能是从数组里挑几个组合在一起
     * <p>
     * <p>
     * 前缀和 + Hash
     * 终于懂了
     *
     * @param nums
     * @param k
     * @return
     */
    public int subarraySum1(int[] nums, int k) {
        int len = nums.length;
        // 前i个数的和为多少？
        int[] preSum = new int[len + 1];
        for (int i = 1; i <= len; i++) {
            preSum[i] = preSum[i - 1] + nums[i - 1];
        }

        Map<Integer, Integer> map = new HashMap<>();
        map.put(0, 1);

        for (int i = 0; i <= len; i++) {
            int sum = preSum[i];
            int pre = sum - k;

            // 有几个前缀和是等于 pre 的，都算作答案
            ans = ans + map.getOrDefault(pre, 0);

            // 有几个前缀和是sum的？
            map.put(sum, map.getOrDefault(sum, 0) + 1);
        }

        return ans;
    }
}
